package cn.ocars.playgame.pencilstudy.ui.components

import android.content.Context
import android.opengl.GLES20
import android.opengl.GLSurfaceView
import android.opengl.Matrix
import android.view.MotionEvent
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10
import kotlin.math.sqrt

/**
 * 书写渲染器类
 * 用于在OpenGL画布上渲染书写笔迹
 */
class WritingRenderer(
    private val context: Context,
    private val character: String,
    private val expectedStrokeCount: Int,
    private val onWritingComplete: (List<StrokeData>) -> Unit
) : GLSurfaceView.Renderer {

    private var glView: GLSurfaceView? = null
    private val strokes = mutableListOf<StrokeData>()
    private var currentStroke = mutableListOf<Float>()
    private var currentWidths = mutableListOf<Float>()
    
    // OpenGL相关变量
    private var program = 0
    private var positionHandle = 0
    private var colorHandle = 0
    private var mvpMatrixHandle = 0
    private val mvpMatrix = FloatArray(16)
    private val projectionMatrix = FloatArray(16)
    private val viewMatrix = FloatArray(16)
    
    // 顶点着色器代码
    private val vertexShaderCode =
        "uniform mat4 uMVPMatrix;" +
        "attribute vec4 vPosition;" +
        "void main() {" +
        "  gl_Position = uMVPMatrix * vPosition;" +
        "}"
    
    // 片段着色器代码
    private val fragmentShaderCode =
        "precision mediump float;" +
        "uniform vec4 vColor;" +
        "void main() {" +
        "  gl_FragColor = vColor;" +
        "}"
    
    fun setGLView(view: GLSurfaceView) {
        this.glView = view
    }
    
    fun handleTouchEvent(event: MotionEvent, width: Int, height: Int): Boolean {
        val x = (event.x / width.toFloat()) * 2 - 1
        val y = -((event.y / height.toFloat()) * 2 - 1)
        
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                currentStroke.clear()
                currentWidths.clear()
                currentStroke.add(x)
                currentStroke.add(y)
                currentStroke.add(0f)
                currentWidths.add(4.0f) // 默认线宽
            }
            MotionEvent.ACTION_MOVE -> {
                currentStroke.add(x)
                currentStroke.add(y)
                currentStroke.add(0f)
                currentWidths.add(4.0f) // 默认线宽
                updateCurrentStroke()
            }
            MotionEvent.ACTION_UP -> {
                if (currentStroke.size >= 3) {
                    strokes.add(StrokeData(currentStroke.toList(), currentWidths.toList()))
                    if (strokes.size >= expectedStrokeCount) {
                        onWritingComplete(strokes)
                    }
                }
                currentStroke.clear()
                currentWidths.clear()
            }
        }
        
        glView?.requestRender()
        return true
    }
    
    fun clear() {
        strokes.clear()
        currentStroke.clear()
        currentWidths.clear()
        glView?.requestRender()
    }
    
    private fun updateCurrentStroke() {
        glView?.requestRender()
    }
    
    override fun onSurfaceCreated(unused: GL10, config: EGLConfig) {
        GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f)
        
        // 准备着色器和OpenGL程序
        val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)
        val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)
        
        program = GLES20.glCreateProgram()
        GLES20.glAttachShader(program, vertexShader)
        GLES20.glAttachShader(program, fragmentShader)
        GLES20.glLinkProgram(program)
        
        positionHandle = GLES20.glGetAttribLocation(program, "vPosition")
        colorHandle = GLES20.glGetUniformLocation(program, "vColor")
        mvpMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix")
    }
    
    override fun onSurfaceChanged(unused: GL10, width: Int, height: Int) {
        GLES20.glViewport(0, 0, width, height)
        
        val ratio = width.toFloat() / height.toFloat()
        Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1f, 1f, 3f, 7f)
    }
    
    override fun onDrawFrame(unused: GL10) {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
        
        // 设置相机位置
        Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, -3f, 0f, 0f, 0f, 0f, 1f, 0f)
        
        // 计算变换矩阵
        Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, viewMatrix, 0)
        
        // 使用OpenGL程序
        GLES20.glUseProgram(program)
        
        // 启用顶点数组
        GLES20.glEnableVertexAttribArray(positionHandle)
        
        // 绘制所有已完成的笔画
        for (stroke in strokes) {
            drawStroke(stroke.vertices, stroke.widths, 0.0f, 0.0f, 0.0f, 1.0f)
        }
        
        // 绘制当前正在绘制的笔画
        if (currentStroke.isNotEmpty()) {
            drawStroke(currentStroke.toList(), currentWidths.toList(), 0.0f, 0.0f, 1.0f, 1.0f)
        }
        
        // 禁用顶点数组
        GLES20.glDisableVertexAttribArray(positionHandle)
    }
    
    private fun drawStroke(vertices: List<Float>, widths: List<Float>, r: Float, g: Float, b: Float, a: Float) {
        if (vertices.size < 6) return // 至少需要两个点
        
        // 准备顶点数据
        val vertexBuffer = ByteBuffer.allocateDirect(vertices.size * 4)
            .order(ByteOrder.nativeOrder())
            .asFloatBuffer()
        vertexBuffer.put(vertices.toFloatArray())
        vertexBuffer.position(0)
        
        // 设置顶点位置
        GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer)
        
        // 设置颜色
        GLES20.glUniform4f(colorHandle, r, g, b, a)
        
        // 设置变换矩阵
        GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, mvpMatrix, 0)
        
        // 绘制线条
        GLES20.glLineWidth(widths[0]) // 使用第一个点的线宽
        GLES20.glDrawArrays(GLES20.GL_LINE_STRIP, 0, vertices.size / 3)
    }
    
    private fun loadShader(type: Int, shaderCode: String): Int {
        val shader = GLES20.glCreateShader(type)
        GLES20.glShaderSource(shader, shaderCode)
        GLES20.glCompileShader(shader)
        return shader
    }
}